package com.pearl.security.multiloginreject.demo.config;

import com.pearl.security.multiloginreject.demo.handler.*;
import com.pearl.security.multiloginreject.demo.session.memery.PearlSessionInformationExpiredStrategy;
import com.pearl.security.multiloginreject.demo.session.redis.JsonSessionInformationExpiredStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;


/**
 * 配置类：内存模式
 *
 * @author TangDan
 * @version 1.0
 * @since 2023/5/24
 */
@Configuration
public class RedisSecurityConfig {

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(e -> {
            e.anyRequest().authenticated();
        });
        http.formLogin(formLogin -> formLogin.usernameParameter("username"));
        // 开启表单登录
        http.formLogin(e -> {
            e.successHandler(new JsonAuthenticationSuccessHandler()) // 登录成功处理器
                    .failureHandler(new JsonAuthenticationFailureHandler());// 登录失败处理器
        });

        // 异常配置
        http.exceptionHandling(e -> {
            e.accessDeniedHandler(new JsonAccessDeniedHandler()) // 权限不足
                    .authenticationEntryPoint(new JsonAuthenticationEntryPoint());// 认证入口
        });
        // 注销登录
        http.logout(e -> {
            e.logoutSuccessHandler(new JsonLogoutSuccessHandler()); //  自定义注销成功处理器
        });
        // 关闭 CSRF
        http.csrf(AbstractHttpConfigurer::disable);
        // 会话管理
        http.sessionManagement(session -> session
                // 并发控制配置
                .sessionConcurrency(sessionCConcurrency -> {
                    sessionCConcurrency
                            .expiredSessionStrategy(new JsonSessionInformationExpiredStrategy());
                })
                //.sessionAuthenticationStrategy(new ExclusiveSessionStrategy()) // 添加自定义认证会话策略
                .maximumSessions(1)); // 用户最大会话数为 1，后面的登陆就会自动踢掉前面的登陆
        //.maxSessionsPreventsLogin(true)); // 当前已登录时，阻止其他登录
        // 2. Redis 模式

        return http.build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
